#pragma once

#include <vector>

#include "BaseBook.h"

namespace mdtx::punch
{
    /**
     * @brief Simple local orderbook
     *
     * @tparam QT quote type
     */
    template <typename QT>
    class LocalBook : public BaseBook<QT>
    {
    public:
        using base = BaseBook<QT>;
        using typename base::order_type;
        using typename base::id_type;
        using typename base::bid_queue_type;
        using typename base::ask_queue_type;
        using order_queue_type = std::vector<order_type>;

    private:
        size_t n, norder, offset;
        std::vector<id_type> seq_list;
        std::vector<bid_queue_type> bid_list;
        std::vector<ask_queue_type> ask_list;
        std::vector<order_queue_type> order_list;

        size_t offset_idx(id_type ins_id) const
        {
            return ins_id - offset;
        }

    public:
        /**
         * @brief Construct a new LocalBook object
         *
         * @param n number of instruments
         * @param offset offset of instrument id
         */
        LocalBook(size_t n, size_t offset = 0)
            : n(n), norder(), offset(offset), seq_list(n, id_type{}), bid_list(n), ask_list(n), order_list(n)
        {
        }

        auto num_instr() const { return n; }
        auto num_order() const { return norder; }
        size_t num_order(id_type ins_id) const override { return seq_list[offset_idx(ins_id)]; }

        order_type &new_order(id_type ins_id, const order_type &order) override
        {
            auto idx = offset_idx(ins_id);
            // push new order to list
            auto &list = order_list[idx];
            list.push_back(order);
            // assign proper sequence id
            auto &new_order = list.back();
            new_order.set_seq(seq_list[idx]++);
            // simple book keeping
            norder++;
            return new_order;
        }

        bid_queue_type &bid(id_type ins_id) override { return bid_list[offset_idx(ins_id)]; }
        const bid_queue_type &bid(id_type ins_id) const override { return bid_list[offset_idx(ins_id)]; }

        ask_queue_type &ask(id_type ins_id) override { return ask_list[offset_idx(ins_id)]; }
        const ask_queue_type &ask(id_type ins_id) const override { return ask_list[offset_idx(ins_id)]; }

        order_type &order(id_type ins_id, id_type seq_id) override { return order_list[offset_idx(ins_id)][seq_id]; }
        const order_type &order(id_type ins_id, id_type seq_id) const override { return order_list[offset_idx(ins_id)][seq_id]; }

        // order list is local, no need to implement on_order, updates are made by ref
    };
}
